package com.facebook.drawee.drawable;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;

import com.facebook.common.internal.Preconditions;
import com.facebook.common.internal.VisibleForTesting;

import java.lang.ref.WeakReference;
import java.util.Arrays;

import javax.annotation.Nullable;

public final class RoundedBitmapDrawable extends BitmapDrawable implements Rounded, TransformAwareDrawable {
    private boolean mIsCircle;
    private boolean mRadiiNonZero;
    private final float[] mCornerRadii;
    @VisibleForTesting
    private float[] mBorderRadii;
    @VisibleForTesting
    private RectF mRootBounds;
    @VisibleForTesting
    private RectF mPrevRootBounds;
    @VisibleForTesting
    private RectF mBitmapBounds;
    @VisibleForTesting
    private RectF mDrawableBounds;
    @VisibleForTesting
    private Matrix mBoundsTransform;
    @VisibleForTesting
    private Matrix mPrevBoundsTransform;
    @VisibleForTesting
    private Matrix mParentTransform;
    @VisibleForTesting
    private Matrix mPrevParentTransform;
    @VisibleForTesting
    private Matrix mInverseParentTransform;
    @VisibleForTesting
    private Matrix mTransform;
    private float mBorderWidth;
    private int mBorderColor;
    private float mPadding;
    private final Path mPath;
    private final Path mBorderPath;
    private boolean mIsPathDirty;
    private final Paint mPaint;
    private final Paint mBorderPaint;
    private boolean mIsShaderTransformDirty;
    private WeakReference<Bitmap> mLastBitmap;
    @Nullable
    private TransformCallback mTransformCallback;

    private RoundedBitmapDrawable(Resources resources, Bitmap bitmap, @Nullable Paint paint) {
        super(resources, bitmap);
        this.mIsCircle = false;
        this.mRadiiNonZero = false;
        this.mCornerRadii = new float[8];
        this.mBorderRadii = new float[8];
        this.mRootBounds = new RectF();
        this.mPrevRootBounds = new RectF();
        this.mBitmapBounds = new RectF();
        this.mDrawableBounds = new RectF();
        this.mBoundsTransform = new Matrix();
        this.mPrevBoundsTransform = new Matrix();
        this.mParentTransform = new Matrix();
        this.mPrevParentTransform = new Matrix();
        this.mInverseParentTransform = new Matrix();
        this.mTransform = new Matrix();
        this.mBorderWidth = 0f;
        this.mBorderColor = 0;
        this.mPadding = 0f;
        this.mPath = new Path();
        this.mBorderPath = new Path();
        this.mIsPathDirty = true;
        this.mPaint = new Paint();
        this.mBorderPaint = new Paint(1);
        this.mIsShaderTransformDirty = true;
        if (paint != null) {
            this.mPaint.set(paint);
        }
        this.mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        this.mBorderPaint.setStyle(Paint.Style.STROKE);
    }

    public static RoundedBitmapDrawable fromBitmapDrawable(Resources resources, BitmapDrawable bitmapDrawable) {
        return new RoundedBitmapDrawable(resources, bitmapDrawable.getBitmap(), bitmapDrawable.getPaint());
    }

    public final void setPadding(float padding) {
        if (this.mPadding != padding) {
            this.mPadding = padding;
            this.mIsPathDirty = true;
            this.invalidateSelf();
        }
    }

    public final void setBorder(int color, float width) {
        if (this.mBorderColor != color || this.mBorderWidth != width) {
            this.mBorderColor = color;
            this.mBorderWidth = width;
            this.mIsPathDirty = true;
            this.invalidateSelf();
        }
    }

    public final void setTransformCallback(@Nullable TransformCallback arg1) {
        this.mTransformCallback = arg1;
    }

    public final void setCircle(boolean isCircle) {
        this.mIsCircle = isCircle;
        this.mIsPathDirty = true;
        this.invalidateSelf();
    }

    public final void setRadii(float[] radii) {
        if (radii == null) {
            Arrays.fill(this.mCornerRadii, 0f);
            this.mRadiiNonZero = false;
        } else {
            Preconditions.checkArgument(radii.length == 8, "radii should have exactly 8 values");
            System.arraycopy(radii, 0, this.mCornerRadii, 0, 8);
            this.mRadiiNonZero = false;
            for (int i = 0; i < 8; ++i) {
                mRadiiNonZero |= (radii[i] > 0);
            }
        }
        this.mIsPathDirty = true;
        this.invalidateSelf();
    }

    public final void setRadius() {
        Preconditions.checkState(true);
        Arrays.fill(this.mCornerRadii, 0f);
        this.mRadiiNonZero = false;
        this.mIsPathDirty = true;
        this.invalidateSelf();
    }

    public final void draw(Canvas canvas) {
        boolean shouldRound = (this.mIsCircle) || (this.mRadiiNonZero) || this.mBorderWidth > 0f;
        if (!shouldRound) {
            super.draw(canvas);
        } else {
            if (this.mTransformCallback != null) {
                this.mTransformCallback.getTransform(this.mParentTransform);
                this.mTransformCallback.getRootBounds(this.mRootBounds);
            } else {
                this.mParentTransform.reset();
                this.mRootBounds.set(this.getBounds());
            }

            this.mBitmapBounds.set(0f, 0f, (float) this.getBitmap().getWidth(), (float) this.getBitmap().getHeight());
            this.mDrawableBounds.set(this.getBounds());
            this.mBoundsTransform.setRectToRect(this.mBitmapBounds, this.mDrawableBounds, Matrix.ScaleToFit.FILL);
            if (!this.mParentTransform.equals(this.mPrevParentTransform) || !this.mBoundsTransform.equals(this.mPrevBoundsTransform)) {
                this.mIsShaderTransformDirty = true;
                this.mParentTransform.invert(this.mInverseParentTransform);
                this.mTransform.set(this.mParentTransform);
                this.mTransform.preConcat(this.mBoundsTransform);
                this.mPrevParentTransform.set(this.mParentTransform);
                this.mPrevBoundsTransform.set(this.mBoundsTransform);
            }

            if (!this.mRootBounds.equals(this.mPrevRootBounds)) {
                this.mIsPathDirty = true;
                this.mPrevRootBounds.set(this.mRootBounds);
            }

            if (this.mIsPathDirty) {
                this.mBorderPath.reset();
                this.mRootBounds.inset(this.mBorderWidth / 2f, this.mBorderWidth / 2f);
                if (this.mIsCircle) {
                    this.mBorderPath.addCircle(this.mRootBounds.centerX(),
                            this.mRootBounds.centerY(),
                            Math.min(this.mRootBounds.width(),
                                    this.mRootBounds.height()) / 2f,
                            Path.Direction.CW);
                } else {
                    for (int i = 0; i < 8; ++i) {
                        this.mBorderRadii[i] = this.mCornerRadii[i] + this.mPadding - this.mBorderWidth / 2f;
                    }

                    this.mBorderPath.addRoundRect(this.mRootBounds, this.mBorderRadii, Path.Direction.CW);
                }

                this.mRootBounds.inset(-this.mBorderWidth / 2f, -this.mBorderWidth / 2f);
                this.mPath.reset();
                this.mRootBounds.inset(this.mPadding, this.mPadding);
                if (this.mIsCircle) {
                    this.mPath.addCircle(this.mRootBounds.centerX(),
                            this.mRootBounds.centerY(),
                            Math.min(this.mRootBounds.width(),
                                    this.mRootBounds.height()) / 2f,
                            Path.Direction.CW);
                } else {
                    this.mPath.addRoundRect(this.mRootBounds, this.mCornerRadii, Path.Direction.CW);
                }
                this.mRootBounds.inset(-this.mPadding, -this.mPadding);
                this.mPath.setFillType(Path.FillType.WINDING);
                this.mIsPathDirty = false;
            }

            Bitmap bitmap = this.getBitmap();
            if (this.mLastBitmap == null || this.mLastBitmap.get() != bitmap) {
                this.mLastBitmap = new WeakReference(bitmap);
                this.mPaint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
                this.mIsShaderTransformDirty = true;
            }

            if (this.mIsShaderTransformDirty) {
                this.mPaint.getShader().setLocalMatrix(this.mTransform);
                this.mIsShaderTransformDirty = false;
            }

            int saveCount = canvas.save();
            canvas.concat(this.mInverseParentTransform);
            canvas.drawPath(this.mPath, this.mPaint);
            if (this.mBorderWidth > 0f) {
                this.mBorderPaint.setStrokeWidth(this.mBorderWidth);
                this.mBorderPaint.setColor(DrawableUtils.multiplyColorAlpha(this.mBorderColor, this.mPaint.getAlpha()));
                canvas.drawPath(this.mBorderPath, this.mBorderPaint);
            }
            canvas.restoreToCount(saveCount);
        }
    }

    public final void setAlpha(int alpha) {
        if (alpha != this.mPaint.getAlpha()) {
            this.mPaint.setAlpha(alpha);
            this.invalidateSelf();
        }
    }

    public final void setColorFilter(ColorFilter colorFilter) {
        this.mPaint.setColorFilter(colorFilter);
        super.setColorFilter(colorFilter);
    }
}

